EXAMPLE for device support that uses VME, PCI, .. on an operating system like vxWorks that allows direct register access Assume an analog input board with registers. These are typically memory-mapped to some base address in memory. Details depend on the hardware and OS. We want to be able to attach one or more records which each read one of the 'channels' from the board. The INP link provides the channel number. −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− record(ai, "$(user):reg0") { field(DTYP, "hwreg") field(INP, "0") field(SCAN, "1 second") } record(ai, "$(user):reg2") { field(DTYP, "hwreg") field(INP, "2") field(SCAN, "1 second") } −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− # dbd file that links DTYP="hwreg" to devAiHW device(ai, CONSTANT, devAiHW, "hwreg") −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− #include #include #include #include "alarm.h" #include "dbDefs.h" #include "dbAccess.h" #include "recGbl.h" #include "recSup.h" #include "devSup.h" #include "devLib.h" #include "link.h" #include "aiRecord.h" #include "epicsExport.h" static long init_record(aiRecord *rec) { // Read channel number from INP link short channel; recGblInitConstantLink(&rec−>inp, DBF_SHORT, &channel); // Exact base address would depend on hardware, // jumper settings, OS, ... // The manual for the board would help figure this out. // For Linux, you might have to do this: // // int fd = open("/dev/that_piece_of_hardware", O_RDWR); // short *base = mmap(...., PROT_READ, ...., fd, ....); // // Assume this is the base address: short *base = (short *) 0x12344532; // Assume the first register is a version code, // and we skip that. // Then follow the registers for channel 0, channel 1, ... short *register = &base[1 + channel]; // Just in case, we use an EPICS call for vxWorks and RTEMS // that checks if there is actually anything at that address short test; if (devReadProbe(2, register, &test) != 0) { printf("Dude, there is no AI board at 0x%x\n", base); rec->pact = 1; } /* device private (dpvt) is where we can park our device data */ rec−>dpvt = register; return 0; } static long read_ai(aiRecord *rec) { short *register = (short *) rec−>dpvt; // Two basic options: // Just read the register. // FAST, but risks bus error (CRASH) when // board removed at runtime rec−>rval = *register; // Other option would be to always use // if (devReadProbe(2, register, &rec->rval) != 0).. // which is SAFE, but slower rec−>udf = FALSE; return 0; } /* Create the device support entry table */ struct { long number; DEVSUPFUN report; DEVSUPFUN init; DEVSUPFUN init_record; DEVSUPFUN get_ioint_info; DEVSUPFUN read_ai; DEVSUPFUN special_linconv; } devAiHW = { 6, NULL, NULL, init_record, NULL, read_ai, NULL }; epicsExportAddress(dset, devAiHW);